home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / doom / axxwar_1.zip / SOURCES / BLAZE.QC < prev    next >
Text File  |  1997-03-13  |  18KB  |  739 lines

  1. // AxxWars 0.8
  2.  
  3. //=============================================================================
  4. // Blaze Gun version 1.2
  5. //
  6. // 2/6/97 by Jonathan E. Wright <nelno@interpath.com>
  7. //
  8. // all original code, not based on anything except the original Quake C
  9. // code from id software.
  10. //=============================================================================
  11.  
  12. // How it works:
  13. // The flame is simply your basic flame model turned 90 degress on it's side
  14. // when it is shot.  When it impacts something that has health > 0 and DAMAGE_AIM
  15. // it sets it's location to that entity's origin, and it's next think becomes
  16. // blaze_stick.  blaze_stick is responsible for following the burning entity,
  17. // checking for water, determining if there is another entity nearby to burn
  18. // and burning the entity every so often.  The time counter for each burn is kept
  19. // in the flame's attack_finished field, so the entity does not have to be burnt
  20. // each time the flame follows it.  When the entity dies, or the flame is submersed
  21. // in water the flame is removed and no more damage is done from that flame.
  22.  
  23. // if you have solid bodies that are respawnable (ie. in the BodyQue) you
  24. // need to call blaze_switchentity when the bodies are copied or else a
  25. // respawned entity can come back with flames on it.
  26.  
  27. /*
  28. ================
  29. macros
  30. ================
  31. */
  32. $cd id1/models/player_4
  33. $origin 0 -6 24
  34. $base base        
  35. $skin skin
  36.  
  37. //
  38. // running
  39. //
  40. $frame axrun1 axrun2 axrun3 axrun4 axrun5 axrun6
  41.  
  42. $frame rockrun1 rockrun2 rockrun3 rockrun4 rockrun5 rockrun6
  43.  
  44. //
  45. // standing
  46. //
  47. $frame stand1 stand2 stand3 stand4 stand5
  48.  
  49. $frame axstnd1 axstnd2 axstnd3 axstnd4 axstnd5 axstnd6
  50. $frame axstnd7 axstnd8 axstnd9 axstnd10 axstnd11 axstnd12
  51.  
  52.  
  53. //
  54. // pain
  55. //
  56. $frame axpain1 axpain2 axpain3 axpain4 axpain5 axpain6
  57.  
  58. $frame pain1 pain2 pain3 pain4 pain5 pain6
  59.  
  60.  
  61. //
  62. // death
  63. //
  64.  
  65. $frame axdeth1 axdeth2 axdeth3 axdeth4 axdeth5 axdeth6
  66. $frame axdeth7 axdeth8 axdeth9
  67.  
  68. $frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8
  69. $frame deatha9 deatha10 deatha11
  70.  
  71. $frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
  72. $frame deathb9
  73.  
  74. $frame deathc1 deathc2 deathc3 deathc4 deathc5 deathc6 deathc7 deathc8
  75. $frame deathc9 deathc10 deathc11 deathc12 deathc13 deathc14 deathc15
  76.  
  77. $frame deathd1 deathd2 deathd3 deathd4 deathd5 deathd6 deathd7
  78. $frame deathd8 deathd9
  79.  
  80. $frame deathe1 deathe2 deathe3 deathe4 deathe5 deathe6 deathe7
  81. $frame deathe8 deathe9
  82.  
  83. //
  84. // attacks
  85. //
  86. $frame nailatt1 nailatt2
  87.  
  88. $frame light1 light2
  89.  
  90. $frame rockatt1 rockatt2 rockatt3 rockatt4 rockatt5 rockatt6
  91.  
  92. $frame shotatt1 shotatt2 shotatt3 shotatt4 shotatt5 shotatt6
  93.  
  94. $frame axatt1 axatt2 axatt3 axatt4 axatt5 axatt6
  95.  
  96. $frame axattb1 axattb2 axattb3 axattb4 axattb5 axattb6
  97.  
  98. $frame axattc1 axattc2 axattc3 axattc4 axattc5 axattc6
  99.  
  100. $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
  101.  
  102. /*
  103. ================
  104. function prototypes
  105. ================
  106. */
  107.  
  108. void () player_run;
  109. void () BecomeExplosion;
  110. void () SuperDamageSound;
  111.  
  112. /*
  113. ================
  114. global vars
  115. ================
  116. */
  117.  
  118. // keeps track of the number of flames so that a maximum of flames
  119. // will not be exceeded, causing Quake to bog down
  120.  
  121. float   current_flames;
  122.  
  123. /*
  124. ==================
  125. constants
  126. ==================
  127. */
  128. //float   IT_BLAZEGUN = 132;
  129.  
  130. /*
  131. ============
  132. functions
  133. ============
  134. */
  135.  
  136. void () blaze_precache =
  137. {
  138.   precache_model2 ("progs/flame2.mdl");
  139.   precache_sound2 ("blaze/flhit1.wav");
  140.   precache_sound2 ("blaze/flshot1.wav");
  141.   precache_sound2 ("blaze/flhiss1.wav");
  142. };
  143.  
  144. /*
  145. ===============
  146. blaze_extinguishentity
  147.  
  148. called when a respawnable entity is removed without being killed (ie.
  149. when Cujo is deactivated).  Prevents the respawned entity from burning.
  150. ===============
  151. */
  152. /*
  153. void (entity old_ent) blaze_extinguishentity =
  154. {
  155.   local   entity  head, temp;
  156.  
  157.   head = nextent (world);
  158.  
  159.   while (head)
  160.   {
  161.     head = find (head, classname, "fire");
  162.  
  163.     if ((head != world) && (head.enemy == old_ent))
  164.     {
  165.       temp = nextent (head);
  166.       current_flames = current_flames - 1;
  167.       remove (head);
  168.       head = temp;
  169.     }
  170.     else if (head != world) head = nextent (head);
  171.   }
  172. };
  173. */
  174.  
  175. void (entity old_ent) blaze_extinguishentity =
  176. {
  177.   local   entity  head, temp;
  178.   local   float   i;
  179.   local   string  temp_text;
  180.  
  181.   head = nextent (world);
  182.  
  183.   while (head)
  184.   {
  185.     if ((head.classname == "fire") && //(vlen (head.origin - old_ent.origin) < 100))
  186.         (head.enemy == old_ent))
  187.     {
  188.       temp = nextent (head);
  189.       head.enemy.dmg_inflictor = world;
  190.       current_flames = current_flames - 1;
  191.       remove (head);
  192.       head = temp;
  193.     }
  194.     else head = nextent (head);
  195.   }
  196. };
  197.  
  198. /*
  199. ===============
  200. blaze_switchentity
  201.  
  202. called when an entities corpse is copied to the body que, prevents the
  203. respawning entity from being still engulfed in flames while the body
  204. can still burn
  205. ===============
  206. */
  207.  
  208. void (entity old_ent, entity new_ent) blaze_switchentity =
  209. {
  210.   local   entity  head;
  211.  
  212.   head = nextent (world);
  213.  
  214.   while (head)
  215.   {
  216.     head = find (head, classname, "fire");
  217.  
  218.     if ((head != world) && (head.enemy == old_ent))
  219.     {
  220.       head.enemy = new_ent;
  221.       setorigin (head, new_ent.origin);
  222.     }
  223.     else if (head != world) head = nextent (head);
  224.   }
  225. };
  226.  
  227. /*
  228. ===============
  229. blaze_spread
  230.  
  231. called by blaze_stick.
  232.  
  233. creates a new flame entity which will stick to and burn entity "fuel"
  234. ===============
  235. */
  236.  
  237. void () blaze_stick;
  238.  
  239. void (entity fuel) blaze_spread =
  240. {
  241.   local   entity   new_flame;
  242.  
  243.   // don't catch the same entity on fire again!
  244.   // don't catch anything that can't take damage
  245.   // and don't catch teammates in teamplay
  246.   if ((teamplay == 1) && (fuel.team != self.owner.team))
  247.   {
  248.     return;
  249.   }
  250.   else if ((fuel.takedamage != DAMAGE_AIM) || (current_flames >= 30))
  251.   {
  252.      return;
  253.   }
  254.   else if ((fuel.classname == "player") && (random () > 0.75))
  255.   {
  256.     return;
  257.   }
  258.   else if (random () > 0.5)
  259.   {
  260.     return;
  261.   }
  262.  
  263.   current_flames = current_flames + 1;
  264.  
  265.   if (fuel.classname == "player")
  266.   {
  267.     bprint (fuel.netname);
  268.     bprint (" is on fire!!\n");
  269.   }
  270.   else if (fuel.classname == "cujo")
  271.     sprint (fuel.owner, "Your dog is aflame!!\n");
  272.  
  273.   new_flame = spawn ();
  274.  
  275.   // set the sucker on fire!
  276.   new_flame.enemy = fuel;
  277.   new_flame.solid = SOLID_NOT;
  278.   new_flame.angles_x = 0;
  279.  
  280.   new_flame.movetype = MOVETYPE_NONE;
  281.   new_flame.effects = EF_DIMLIGHT;
  282.   new_flame.takedamage = DAMAGE_NO;
  283.   new_flame.classname = "fire";
  284.   new_flame.targetname = "";
  285.  
  286.   new_flame.think = blaze_stick;
  287.   new_flame.nextthink = time;
  288.  
  289.   // always points back to the player who fired the original flame
  290.   // so monsters get mad at player, not at flames!
  291.   new_flame.owner = self.owner;
  292.  
  293.   setmodel (new_flame, "progs/flame2.mdl");
  294.   setsize (new_flame, '2 2 2', '2 2 2');
  295.   setorigin (new_flame, fuel.origin);
  296. };
  297.  
  298. /*
  299. ===============
  300. blaze_findfuel
  301.  
  302. called by blaze_stick
  303.  
  304. searches for the closest entity within a certain radius.  If a qualifying entity is
  305. found, and a random chance met, the entity is caught on fire by calling blaze_spread.
  306.  
  307. Notice there is a greater chance for players to be caught on fire, since they tend to
  308. move around quite a bit more than monsters, and are less likely to remain near a flame
  309. ===============
  310. */
  311.  
  312. void (float dist) blaze_findfuel =
  313. {
  314.   local   entity   head;
  315.   local   entity   fuel;
  316.   local   float    lastd;
  317.  
  318.   // anything dist units away can catch flame
  319.   head = findradius (self.origin, dist);
  320.   fuel = world;
  321.  
  322.   while (head)
  323.   {
  324.     if (((teamplay == 1) && (head.team != self.owner.team)) || (teamplay != 1))
  325.     {
  326.       if ((head != self.enemy) && (head.takedamage == DAMAGE_AIM))
  327.       {
  328.         // find the distance to the current entity, so we can choose the closest
  329.         // entity within the radius
  330.         lastd = vlen (self.origin - head.origin);
  331.         if (lastd < dist)
  332.         {
  333.           fuel = head;
  334.           dist = lastd;
  335.         }
  336.       }
  337.     }
  338.     head = head.chain;
  339.   }
  340.  
  341.   if ((fuel != world) && (random () < 0.1))
  342.   {
  343.     blaze_spread (fuel);
  344.   }
  345. };
  346.  
  347. /*
  348. ===============
  349. blaze_stick
  350.  
  351. called every frame as the flame's think function.  responsible for control
  352. the flame once it has attached to an entity -- not in flight from the blaze gun!
  353.  
  354. checks for water submersion each frame
  355. ===============
  356. */
  357.  
  358. void () burn_entity;
  359.  
  360. void () blaze_stick =
  361. {
  362.   local   vector   org;
  363.   local   vector   fuelsize, xv, yv, zv;
  364.   local   float    pc;
  365.   local   float    average_width;
  366.  
  367.   pc = pointcontents (self.origin);
  368.   if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME))
  369.   {
  370.     // water extinguished the flame
  371.     sound (self, CHAN_WEAPON, "blaze/flhiss1.wav", 1, ATTN_NORM);
  372.     // reset inflictor so enities don't keep going for water
  373.     self.enemy.dmg_inflictor = world;
  374.     current_flames = current_flames - 1;
  375.     remove (self);
  376.     return;
  377.   }
  378.  
  379.   // a dead player -- put out the flames before they respawn!
  380.   // changed to flame search in CopyBodyToQue
  381. /*
  382.   if (self.enemy.deadflag == DEAD_RESPAWNABLE))
  383.   {
  384.     current_flames = current_flames - 1;
  385.     remove (self);
  386.     return;
  387.   }
  388. */
  389.  
  390.   fuelsize = self.enemy.size;
  391.  
  392.   // it's really the average of x_width and y_width * 2;
  393.   average_width = (fuelsize_x + fuelsize_y) * 0.5;
  394.   blaze_findfuel (average_width);
  395.  
  396.   // make the flames dance, baby! dance!
  397.  
  398.   if (self.enemy.classname == "monster_shambler")
  399.     pc = 0.4;
  400.   else
  401.     pc = 0.1;
  402.  
  403.   fuelsize_x = fuelsize_x * pc * random ();
  404.   if (random () < 0.5)
  405.     fuelsize_x = fuelsize_x * -1;
  406.   fuelsize_y = fuelsize_y * pc * random ();
  407.   if (random () < 0.5)
  408.     fuelsize_y = fuelsize_y * -1;
  409.   fuelsize_z = fuelsize_z * pc * random ();
  410.   if ((random () < 0.5) && (self.enemy.classname != "monster_shambler"))
  411.     fuelsize_z = fuelsize_z * -1;
  412.  
  413.   org = self.enemy.origin + fuelsize;
  414.   setorigin (self, org);
  415.  
  416.   if (self.velocity == '0 0 0') self.avelocity = '0 0 0';
  417.  
  418.   self.think = blaze_stick;
  419.   self.nextthink = time;
  420.  
  421.   // targetname is used as a flag here to determine if the entity
  422.   // has already been determined to be dead and the attack_finished time
  423.   // already increased -- without the flag, the flames won't burn out
  424.   // because the attack_finished time will always be increasing
  425.  
  426.   if ((self.enemy.health <= 0) && (self.targetname == "") &&
  427.        (self.enemy.classname != "monster_zombie"))
  428. //       (self.enemy.classname != "player"))
  429.   {
  430.     self.attack_finished = 7 * random () + time;
  431.     self.targetname = "already_dead";
  432. //    bprint (self.enemy.classname);
  433. //    bprint (" is dead and burning\n");
  434.   }
  435.  
  436.   if (self.attack_finished <= time) burn_entity ();
  437. };
  438.  
  439. /*
  440. ===============
  441. burn_entity -- called by the flame
  442.  
  443. called each time attack_finished <= time, currently every second
  444. responsible for damaging the entity the flame is attached to
  445.  
  446. zombies are a special case and recieve quite a bit more damage than
  447. a normal monster or player so that a few flames and sometimes a single
  448. flame, can gib them
  449. ===============
  450. */
  451.  
  452. void () burn_entity =
  453. {
  454.   if ((self.enemy.health <= 0) || (self.enemy.deadflag == DEAD_RESPAWNABLE))
  455.   {
  456.     current_flames = current_flames - 1;
  457.     remove (self);
  458.     return;
  459.   }
  460.  
  461.   if (self.enemy.classname != "monster_zombie")
  462.     T_Damage (self.enemy, self, self.owner, 6 * random () + 1);
  463.   else
  464.     T_Damage (self.enemy, self, self.owner, 50 * random () + 10);
  465.  
  466.   if (self.enemy.classname == "player")
  467.     centerprint (self.enemy, "You're on fire!\nFind some water or armor!");
  468.  
  469. //  self.think = blaze_stick;
  470. //  self.nextthink = time;
  471.   self.attack_finished = time + 1;
  472. };
  473.  
  474. /*
  475. ===============
  476. blaze_watercheck
  477.  
  478. called as the flame's think function from the time it is fired until it hits
  479. and is removed or catches and entity on fire
  480. ===============
  481. */
  482.  
  483. void() blaze_watercheck =
  484. {
  485.   local float  pc;
  486.  
  487.   pc = pointcontents (self.origin);
  488.   if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME) || (self.attack_finished <= time))
  489.   {
  490.     sound (self, CHAN_WEAPON, "blaze/flhiss1.wav", 1, ATTN_NORM);
  491.     // reset inflictor so enities don't keep going for water
  492.     remove (self);
  493.  
  494.     // make the little grey particles
  495.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  496.     WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  497.     WriteCoord (MSG_BROADCAST, self.origin_x);
  498.     WriteCoord (MSG_BROADCAST, self.origin_y);
  499.     WriteCoord (MSG_BROADCAST, self.origin_z);
  500.  
  501.     return;
  502.   }
  503.  
  504.   self.think = blaze_watercheck;
  505.   self.nextthink = time;
  506. };
  507.  
  508. /*
  509. ===============
  510. blaze_touch
  511.  
  512. the touch function of an in-flight flame.  responsible for setting an
  513. entity aflame when it hits it (if the random chance is met)
  514. ===============
  515. */
  516.  
  517. void() blaze_touch =
  518. {
  519.   local vector org;
  520.  local float  pc;
  521.  
  522.  // for debugging fire extinguishing
  523.  // other = self.owner;
  524.  
  525.   pc = pointcontents (self.origin);
  526.   if (pc == CONTENT_SKY)
  527.   {
  528.     remove (self);
  529.     return;
  530.   }
  531.   else if ((pc == CONTENT_WATER) || (pc == CONTENT_SLIME))
  532.   {
  533.     remove (self);
  534.     return;
  535.   }
  536.  
  537.   sound (self, CHAN_WEAPON, "blaze/flhit1.wav", 1, ATTN_NORM);
  538.  
  539.   org = self.origin - 8*normalize(self.velocity);
  540.  
  541.   if ((other.health) && (other.takedamage == DAMAGE_AIM))
  542.     T_Damage (other, self, self.owner, 15);
  543.   else
  544.   {
  545.     // makes a little debris appear for one frame
  546.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  547.     WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  548.     WriteCoord (MSG_BROADCAST, org_x);
  549.     WriteCoord (MSG_BROADCAST, org_y);
  550.     WriteCoord (MSG_BROADCAST, org_z);
  551.   }
  552.  
  553.   // does some radius damage, < 1/3 that of a rocket
  554.   T_RadiusDamage (self, self.owner, 35, other);
  555.  
  556. // debugging purposes
  557. /*
  558.   bprint ("health=");
  559.   bprint (ftos (other.health));
  560.   if (other.takedamage == DAMAGE_AIM)
  561.     bprint (", DAMAGE_AIM\n");
  562.   else
  563.     bprint (", no damage\n");
  564. */
  565.   if (((teamplay == 1) && (other.team != self.owner.team)) || (teamplay != 1))
  566.   {
  567.     if ((other.health) && (other.takedamage == DAMAGE_AIM))
  568.     {
  569.       if ((random () < 0.6) && (current_flames < 30))
  570.       {
  571.         // set the sucker on fire!
  572.         self.enemy = other;
  573. // used for debugging deathmatch respawns
  574. //      self.enemy = self.owner;
  575.         self.solid = SOLID_NOT;
  576.         self.movetype = MOVETYPE_NONE;
  577.         self.origin = self.enemy.origin;
  578.         self.think = blaze_stick;
  579.         self.nextthink = time;
  580.         self.attack_finished = time + 1;
  581.         self.classname = "fire";
  582.         self.targetname = "";
  583.         // point flame upright
  584.         self.angles_x = 0;
  585.         current_flames = current_flames + 1;
  586.  
  587.         return;
  588.       }
  589.     }
  590.   }
  591.  
  592.   BecomeExplosion ();
  593. };
  594.  
  595.  
  596. /*
  597. ===============
  598. blaze_launch
  599.  
  600. the main firing routine, determines where the flame shoots from and where it will
  601. go to, determines it's velocity, etc.
  602. ===============
  603. */
  604.  
  605. void(float ox) blaze_launch =
  606. {
  607.   local   entity   old;
  608.   local   vector   start, finish, dir;
  609.   local   float    pc;
  610.  
  611.   start = self.origin + '0 0 16' + v_right*ox;
  612.  
  613.   makevectors (self.v_angle);
  614.  
  615.   if (self.ammo_nails < 1)
  616.   {
  617.     self.weapon = W_BestWeapon ();
  618.     W_SetCurrentAmmo ();
  619.     return;
  620.   }
  621.  
  622.   self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  623.   makevectors (self.v_angle);        // is this still used
  624.  
  625.   finish = start + v_forward*600;
  626.   dir = finish - start;
  627.  
  628. // launch the flame
  629.   sound (self, CHAN_WEAPON, "blaze/flshot1.wav", 1, ATTN_NORM);
  630.  
  631.   dir = normalize(dir);
  632.  
  633.   newmis = spawn();
  634.   newmis.owner = self;
  635.   newmis.movetype = MOVETYPE_TOSS;
  636.   newmis.solid = SOLID_BBOX;
  637.   newmis.effects = EF_DIMLIGHT;
  638.   newmis.takedamage = DAMAGE_NO;
  639.   newmis.classname = "blaze_shot";
  640.  
  641.   setmodel (newmis, "progs/flame2.mdl");
  642.   setsize (newmis, '2 2 2', '2 2 2');
  643.  
  644.   setorigin (newmis, start);
  645.  
  646.   // add player's velocity to the flames velocity for maximum effect
  647.   newmis.velocity = (self.velocity * 0.5) + (dir * 1000);
  648.   newmis.angles = vectoangles(newmis.velocity);
  649.   // turn the flame on it's side, widest end away from player
  650.   newmis.angles_x = newmis.angles_x + 90;
  651.  
  652.   // give the player a little kickback
  653.   self.velocity = self.velocity - (dir * 125);
  654.  
  655.   // will burn for 8 seconds
  656.   newmis.attack_finished = time + 8;
  657.   // continously check for water
  658.   newmis.nextthink = time + 0.1;
  659.   newmis.think = blaze_watercheck;
  660.   newmis.touch = blaze_touch;
  661.  
  662. //  launch_flame (start, dir);
  663.   self.punchangle_x = -2;
  664. };
  665.  
  666. void () blaze_attack1 = [$nailatt1, blaze_attack2]
  667. {
  668.   self.effects = self.effects | EF_MUZZLEFLASH;
  669.  
  670. //  if (!self.button0)
  671. //  {
  672. //    player_run ();
  673. //    return;
  674. //  }
  675.  
  676.   self.weaponframe = self.weaponframe + 1;
  677.   if (self.weaponframe == 9) self.weaponframe = 1;
  678.  
  679.   SuperDamageSound();
  680.  
  681.   blaze_launch (4);
  682.  
  683.   self.attack_finished = time + 0.2;
  684. };
  685.  
  686. //============================================================================
  687.  
  688. void () blaze_attack2 = [$nailatt1, blaze_attack3]
  689. {
  690.   if (!self.button0)
  691.   {
  692.     player_run ();
  693.     return;
  694.   }
  695.  
  696.   self.weaponframe = self.weaponframe + 1;
  697.   if (self.weaponframe == 9) self.weaponframe = 1;
  698.  
  699.   self.attack_finished = time + 0.2;
  700. };
  701.  
  702. //============================================================================
  703.  
  704. void () blaze_attack3 = [$nailatt2, blaze_attack4]
  705. {
  706.   self.effects = self.effects | EF_MUZZLEFLASH;
  707.  
  708.   if (!self.button0)
  709.   {
  710.     player_run ();
  711.     return;
  712.   }
  713.  
  714.   self.weaponframe = self.weaponframe + 1;
  715.   if (self.weaponframe == 9) self.weaponframe = 1;
  716.  
  717.   SuperDamageSound();
  718.  
  719.   blaze_launch (-4);
  720.  
  721.   self.attack_finished = time + 0.2;
  722. };
  723.  
  724. //============================================================================
  725.  
  726. void () blaze_attack4 = [$nailatt2, blaze_attack1]
  727. {
  728.   if (!self.button0)
  729.   {
  730.     player_run ();
  731.     return;
  732.   }
  733.  
  734.   self.weaponframe = self.weaponframe + 1;
  735.   if (self.weaponframe == 9) self.weaponframe = 1;
  736.  
  737.   self.attack_finished = time + 0.2;
  738. };
  739.